package com.demo.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author
 * @since
 */
@Configuration
public class GatewayConfig {

  private final List<ViewResolver> viewResolverList;
  private final ServerCodecConfigurer serverCodecConfigurer;

  public GatewayConfig(ObjectProvider<List<ViewResolver>> objectProvider, ServerCodecConfigurer serverCodecConfigurer1){
      this.viewResolverList = objectProvider.getIfAvailable(Collections::emptyList);
      this.serverCodecConfigurer = serverCodecConfigurer1;
  }

  @Bean
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public GlobalFilter sentinelGatewayFilter(){
    return new SentinelGatewayFilter();
  }

  @Bean
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
    return new SentinelGatewayBlockExceptionHandler(viewResolverList, serverCodecConfigurer);
  }

  @PostConstruct
  public void init(){
    initGatewayApiGroup();
    initGatewayRules();
  }

  public void initGatewayRules() {
    Set<GatewayFlowRule> rules = new HashSet<>();
    GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("first_custom_api")
        .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
        .setCount(1)
        .setIntervalSec(1);
    rules.add(gatewayFlowRule);
    GatewayRuleManager.loadRules(rules);
  }

  public void initGatewayApiGroup(){
    Set<ApiDefinition> apiDefinitionSet = new HashSet<>();
    ApiDefinition apiDefinition = new ApiDefinition("first_custom_api");
    apiDefinition.setPredicateItems(new HashSet<ApiPredicateItem>(){
      {
        add(new ApiPathPredicateItem().setPattern("/gateway/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
        add(new ApiPathPredicateItem().setPattern("/sentinel/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
      }
    });
    apiDefinitionSet.add(apiDefinition);
    GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitionSet);
  }

}
